local c = require("colorschemes").get("onelight")
local space = " "

---Set the terminal colors
---@return nil
local function terminal_color()
	vim.g.terrminal_color_0 = c.black
	vim.g.terminal_color_1 = c.red
	vim.g.terminal_color_2 = c.green
	vim.g.terminal_color_3 = c.yellow
	vim.g.terminal_color_4 = c.blue
	vim.g.terminal_color_5 = c.purple
	vim.g.terminal_color_6 = c.cyan
	vim.g.terminal_color_7 = c.white

	vim.g.terminal_color_8 = c.visual_grey
	vim.g.terminal_color_9 = c.dark_red
	vim.g.terminal_color_10 = c.green
	vim.g.terminal_color_11 = c.dark_yellow
	vim.g.terminal_color_12 = c.blue
	vim.g.terminal_color_13 = c.purple
	vim.g.terminal_color_14 = c.cyan
	vim.g.terminal_color_15 = c.grey
	vim.g.terminal_color_background = c.background
	vim.g.terminal_color_foreground = c.foreground
end

local function mt(...)
	local all = {}
	for _, v in pairs({ ... }) do
		for e, a in pairs(v) do
			all[e] = a
		end
	end
	return all
end
local function fb(fg, bg)
	return { fg = fg, bg = bg }
end
local function f(fg)
	return { fg = fg }
end
local function b(bg)
	return { bg = bg }
end
---@diagnostic disable-next-line: unused-function, unused-local
local function p(sp)
	return { sp = sp }
end
local function s(style)
	return { style = style }
end
local function link(l)
	return { link = l }
end

-- styles
-- bold underline undercurl italic reverse
local function highlight(highlights)
	for name, settings in pairs(highlights) do
		local fg = settings.fg and "guifg=" .. settings.fg or "guifg=NONE"
		local bg = settings.bg and "guibg=" .. settings.bg or "guibg=NONE"
		local style = settings.style and "gui=" .. settings.style or "gui=NONE"
		local sp = settings.sp and "guisp=" .. settings.sp or ""
		local gui = space .. style .. space .. fg .. space .. bg .. space .. sp
		if settings.link and (settings.fg == nil and settings.bg == nil and settings.sp == nil) then
			vim.cmd("highlight! link " .. name .. space .. settings.link)
		else
			vim.cmd("highlight " .. name .. gui)
		end
	end
end
local hl = {
	common = {},
	syntax = {},
	langs = {},
	plugins = {},
	git = {},
	treesitter = {},
	transparency = {},
}

hl.common = {
	Red = f(c.red),
	dark_red = f(c.dark_yellow),
	Yellow = f(c.yellow),
	dark_yellow = f(c.dark_yellow),
	Blue = f(c.blue),
	Green = f(c.green),
	Purple = f(c.purple),
	-- 背景颜色
	Normal = fb(c.foreground, c.background),
	-- normal text in non-current window
	-- NormalNC = {},
	Terminal = fb(c.foreground, c.background),
	NormalFloat = link("Normal"),
	FloatBorder = f(c.blue),
	EndOfBuffer = f(c.black),
	Cursor = fb(c.black, c.blue),
	-- the character under the cursor when |language-mapping| is used (see 'guicursor')
	-- Conceal = {},
	-- lCursor = {},
	-- like Cursor, but used when in IME mode |CursorIM|
	-- CursorIM = {},
	ColorColumn = b(c.cursor_grey),
	CursorColumn = b(c.cursor_grey),
	-- 当前行颜色
	CursorLine = b(c.visual_grey),
	-- 当前行号颜色
	CursorLineNr = f(c.red),
	-- 行颜色
	LineNr = f(c.gutter_fg_grey),
	-- directory names (and other special names in listings)
	Directory = f(c.blue),
	SignColumn = fb(c.foreground, c.background),

	Pmenu = b(c.background),
	PmenuSel = fb(c.cursor_grey, c.blue),
	PmenuSbar = b(c.background),
	PmenuThumb = b(c.blue),

	Search = fb(c.black, c.yellow),
	IncSearch = fb(c.grey, c.yellow),
	Question = f(c.purple),
	QuickFixLine = fb(c.black, c.yellow),
	VertSplit = f(c.vertsplit),
	Folded = f(c.grey),
	-- 'foldcolumn'
	-- FoldColumn = {},
	-- '~' and '@' at the end of the window
	NonText = f(c.special_grey),
	-- statusline 背景色
	StatusLine = fb(c.foreground, c.background),
	StatusLineNC = mt(f(c.grey), s("underline")),
	StatusLineTerm = fb(c.foreground, c.background),
	StatusLineTermNC = f(c.grey),
	-- Visual mode selection
	Visual = s("inverse"),
	VisualNOS = link("Visual"),

	-- git diff
	DiffAdd = f("#003e4a"),
	DiffChange = s("underline"),
	DiffDelete = f("#501b20"),
	DiffText = f("#005869"),
	-- DiffAdd = f(c.green),
	-- DiffChange = f(c.yellow),
	-- DiffDelete = f(c.red),
	-- DiffText = f(c.yellow),

	-- git
	diffAdded = f(c.green),
	diffChanged = f(c.yellow),
	diffRemoved = f(c.red),
	diffFile = f(c.yellow),
	diffNewFile = f(c.yellow),
	diffLine = f(c.blue),

	ErrorMsg = f(c.red),
	WarningMsg = f(c.yellow),
	-- 括号匹配颜色
	MatchParen = mt(f(c.blue), s("underline")),
	ModeMsg = link("Normal"),
	-- Area for messages and cmdline
	MsgArea = link("ModeMsg"),
	-- Separator for scrolled messages, `msgsep` flag of 'display'
	MsgSeparator = link("ModeMsg"),
	-- |more-prompt|
	MoreMsg = f(c.green),
	SpellBad = mt(f(c.red), s("underline")),
	SpellCap = f(c.dark_yellow),
	SpellLocal = f(c.dark_yellow),
	-- Unprintable characters: text displayed differently from what it really is.
	-- SpecialKey = f(c.special_grey),
	-- Word that is recognized by the spellchecker as one that is hardly ever used.
	-- SpellRare = f(c.dark_yellow),
	TabLine = f(c.grey),
	TabLineFill = f(c.foreground),
	TabLineSel = f(c.white),
	Title = f(c.green),
	WildMenu = fb(c.black, c.blue),
}

local or_ita = function()
	local ita = require("core.config").ui.italic_comment
	if ita then
		return mt(f(c.comment_grey), s("italic"))
	else
		return f(c.comment_grey)
	end
end
hl.syntax = {
	Comment = or_ita(),
	Constant = f(c.blue),
	String = f(c.green),
	Character = f(c.green),
	Number = f(c.dark_yellow),
	Boolean = f(c.dark_yellow),
	Float = f(c.dark_yellow),
	-- (preferred) any variable name
	Identifier = f(c.foreground),
	Function = f(c.blue),
	Statement = f(c.purple),
	Conditional = f(c.purple),
	Repeat = f(c.purple),
	Label = f(c.red),
	-- "sizeof", "+", "*", ettheme.colors.
	Operator = mt(f(c.cyan), s("italic")),
	Keyword = f(c.red),
	Exception = f(c.purple),
	PreProc = f(c.yellow),
	Include = f(c.blue),
	Define = f(c.purple),
	Macro = f(c.purple),
	PreCondit = f(c.yellow),
	Type = f(c.yellow),
	StorageClass = f(c.yellow),
	Structure = f(c.yellow),
	Typedef = f(c.yellow),
	Special = f(c.blue),
	SpecialChar = f(c.dark_yellow),
	-- Tag = {},
	Delimiter = f(c.foreground),
	-- special things inside a comment
	SpecialComment = f(c.comment_grey),
	-- you can use CTRL-] on this
	-- Debug = {},
	Underlined = s("underline"),
	Bold = "bold",
	Italic = s("italic"),
	-- (preferred) left blank, hidden  |hl-Ignore|
	-- Ignore = {},
	Error = f(c.red),
	Todo = f(c.purple),
}

hl.treesitter = {
	-- For C++/Dart attributes, annotations that can be attached to the code to denote some kind of meta information.
	TSAnnotation = f(c.red),
	-- (unstable)
	TSAttribute = f(c.purple),
	-- For booleans.
	TSBoolean = link("Boolean"),
	-- For characters.
	TSCharacter = link("Character"),
	-- For comment blocks.
	TSComment = link("Comment"),
	-- For keywords related to conditionnals.
	TSConditional = link("Conditional"),
	-- For constants
	TSConstant = link("Constant"),
	-- For constant that are built in the language: `nil` in Lua.
	TSConstBuiltin = f(c.dark_yellow),
	-- For constants that are defined by macros: `NULL` in theme.config.
	TSConstMacro = link("Constant"),
	-- For constructor calls and definitions: `{}` in Lua, and Java constructors.
	TSConstructor = f(c.cyan),
	-- For syntax/parser errors.
	TSError = link("Error"),
	-- For exception related keywords.
	TSException = link("Exception"),
	-- For fields (responsible for making YAML files look rubbish!)
	TSField = f(c.red),
	-- For floats.
	TSFloat = link("Float"),
	-- For function (calls and definitions).
	TSFunction = f(c.blue),
	-- For builtin functions: `table.insert` in Lua.
	TSFuncBuiltin = f(c.blue),
	-- For macro defined fuctions (calls and definitions): each `macro_rules` in Rust.
	TSFuncMacro = f(c.foreground),
	-- For includes: `#include` in C, `use` or `extern crate` in Rust, or `require` in Lua.
	TSInclude = mt(f(c.blue), s("italic")),
	-- For keywords that don't fall in previous categories.
	TSKeyword = f(c.purple),
	-- For keywords used to define a fuction.
	TSKeywordFunction = f(c.purple),
	-- For operators that are English words, e.g. `and`, `as`, `or`.
	TSKeywordOperator = mt(f(c.purple), s("italic")),
	-- for the `return` and `yield` keywords.
	TSKeywordReturn = link("TSKeyword"),
	-- For labels: `label:` in C and `:label:` in Lua.
	TSLabel = mt(f(c.purple), s("italic")),
	-- For method calls and definitions.
	TSMethod = f(c.blue),
	-- For identifiers referring to modules and namespaces.
	TSNamespace = f(c.yellow),
	-- TSNone = {},
	-- For integers.
	TSNumber = link("Number"),
	-- For any operator: `+`, but also `->` and `*` in theme.config.
	TSOperator = link("Operator"),
	-- For parameters of a function.
	TSParameter = mt(f(c.red), s("italic")),
	-- For references to parameters of a function.
	TSParameterReference = f(c.foreground),
	-- Same as `TSField`.
	TSProperty = f(c.red),
	-- For delimiters ie: `.`
	TSPunctDelimiter = link("Delimiter"),
	-- For brackets and parens.
	TSPunctBracket = f(c.foreground),
	-- For special punctutation that does not fall in the catagories before.
	TSPunctSpecial = f(c.foreground),
	-- For keywords related to loops.
	TSRepeat = mt(f(c.purple), s("italic")),
	-- For strings.
	TSString = f(c.green),
	-- For regexes.
	TSStringRegex = f(c.green),
	-- For escape characters within a string.
	TSStringEscape = f(c.cyan),
	-- For strings with special meaning that don't fit into the above categories.
	TSStringSpecial = link("Special"),
	-- For identifiers referring to symbols or atoms.
	TSSymbol = f(c.red),
	-- Tags like html tag names.
	TSTag = f(c.red),
	-- For html tag attributes.
	TSTagAttribute = link("TSProperty"),
	-- Tag delimiter like `<` `>` `/`
	TSTagDelimiter = link("Delimiter"),
	-- For strings considered text in a markup language.
	TSText = f(c.foreground),
	-- For text to be represented with strong.
	TSStrong = mt(f(c.foreground), s("bold")),
	-- For text to be represented with emphasis.
	TSEmphasis = mt(f(c.foreground), s("italic")),
	-- For text to be represented with an underline.
	TSUnderline = mt(f(c.foreground), s("underline")),
	-- For strikethrough text.
	TSStrike = f(c.foreground),
	-- Text that is part of a title.
	TSTitle = f(c.foreground),
	-- Literal text.
	TSLiteral = f(c.foreground),
	-- Any URI like a link or email.
	TSURI = f(c.blue),
	-- For LaTex-like math environments.
	TSMath = f(c.foreground),
	-- For footnotes, text references, citations.
	TSTextReference = link("TSText"),
	-- For text environments of markup languages.
	TSEnvironment = link("Macro"),
	-- For the name/the string indicating the type of text environment.
	TSEnvironmentName = link("Type"),
	-- Text representation of an informational note.
	TSNote = f(c.foreground),
	-- Text representation of a warning note.
	TSWarning = f(c.yellow),
	-- Text representation of a danger note.
	TSDanger = f(c.red),
	-- For types.
	TSType = f(c.yellow),
	-- For builtin types (you guessed it, right ?).
	TSTypeBuiltin = f(c.dark_yellow),
	-- Any variable name that does not have another highlight.
	TSVariable = f(c.red),
	-- Variable names that are defined by the languages, like `this` or `self`.
	TSVariableBuiltin = mt(f(c.yellow), s("italic")),

	-- TreesitterContext = b(gc.visual_grey)
	TreesitterContext = b("#16181c"),
}

hl.langs.c = {}
hl.langs.cpp = {}
hl.langs.py = {}
hl.langs.lua = {}
hl.langs.sh = {}
hl.langs.json = {}
hl.langs.markdown = {}

hl.git = {
	gitcommitComment = f(c.comment_grey),
	gitcommitUnmerged = f(c.green),
	gitcommitOnBranch = {},
	gitcommitBranch = f(c.purple),
	gitcommitDiscardedType = f(c.red),
	gitcommitSelectedType = f(c.green),
	gitcommitHeader = {},
	gitcommitUntrackedFile = f(c.cyan),
	gitcommitDiscardedFile = f(c.red),
	gitcommitSelectedFile = f(c.green),
	gitcommitUnmergedFile = f(c.yellow),
	gitcommitFile = {},
	gitcommitSummary = f(c.white),
	gitcommitOverflow = f(c.red),
	gitcommitNoBranch = f(c.purple),
	gitcommitUntracked = f(c.grey),
	gitcommitDiscarded = f(c.grey),
	gitcommitSelected = f(c.grey),
	gitcommitDiscardedArrow = f(c.red),
	gitcommitSelectedArrow = f(c.green),
	gitcommitUnmergedArrow = f(c.cyan),
}

hl.plugins.lsp = {
	LspDiagnosticsDefaultError = link("Error"),
	LspDiagnosticsDefaultWarning = f(c.yellow),
	LspDiagnosticsDefaultInformation = f("blue"),
	LspDiagnosticsDefaultHint = f("cyan"),

	DiagnosticLineNrError = mt(fb("#FF0000", "#51202A"), s("bold")),
	DiagnosticLineNrWarn = mt(fb("#FFA500", "#51412A"), s("bold")),
	DiagnosticLineNrInfo = mt(fb("#00FFFF", "#1E535D"), s("bold")),
	DiagnosticLineNrHint = mt(fb("#0000FF", "#1E205D"), s("bold")),

	LspDiagnosticsSignError = link("LspDiagnosticsDefaultError"),
	LspDiagnosticsSignWarning = link("LspDiagnosticsDefaultWarning"),
	LspDiagnosticsSignInformation = link("LspDiagnosticsDefaultInformation"),
	LspDiagnosticsSignHint = link("LspDiagnosticsDefaultHint"),

	LspDiagnosticsUnderlineError = mt(f(c.red), s("undercurl")),
	LspDiagnosticsUnderlineWarning = mt(f(c.yellow), s("undercurl")),
	LspDiagnosticsUnderlineInformation = mt(f(c.blue), s("undercurl")),
	LspDiagnosticsUnderlineHint = s("undercurl"),

	LspDiagnosticsVirtualTextError = link("LspDiagnosticsDefaultError"),
	LspDiagnosticsVirtualTextWarning = link("LspDiagnosticsDefaultWarning"),
	LspDiagnosticsVirtualTextInformation = link("LspDiagnosticsDefaultInformation"),
	LspDiagnosticsVirtualTextHint = link("LspDiagnosticsDefaultHint"),

	LspReferenceText = b(c.background), -- used for highlighting "text" references
	LspReferenceRead = link("LspReferenceText"), -- used for highlighting "read" references
	LspReferenceWrite = link("LspReferenceText"), -- used for highlighting "write" references
	DiagnosticHint = link("LspDiagnosticsDefaultHint"),
	DiagnosticError = link("LspDiagnosticsDefaultError"),
	DiagnosticWarn = link("LspDiagnosticsDefaultWarning"),
	DiagnosticInformation = link("LspDiagnosticsDefaultInformation"),

	DiagnosticSignError = link("LspDiagnosticsSignError"),
	DiagnosticSignWarn = link("LspDiagnosticsSignWarning"),
	DiagnosticSignInfo = link("LspDiagnosticsSignInformation"),
	DiagnosticSignHint = link("LspDiagnosticsSignHint"),

	DiagnosticUnderlineError = link("LspDiagnosticsUnderlineError"),
	DiagnosticUnderlineWarn = link("LspDiagnosticsUnderlineWarning"),
	DiagnosticUnderlineInfo = link("LspDiagnosticsUnderlineInformation"),
	DiagnosticUnderlineHint = link("LspDiagnosticsUnderlineHint"),

	DiagnosticVirtualTextError = link("LspDiagnosticsVirtualTextError"),
	DiagnosticVirtualTextWarn = link("LspDiagnosticsVirtualTextWarning"),
	DiagnosticVirtualTextInfo = link("LspDiagnosticsVirtualTextInformation"),
	DiagnosticVirtualTextHint = link("LspDiagnosticsVirtualTextHint"),
}

hl.plugins.cmp = {
	CmpItemAbbr = f(c.foreground),
	CmpItemAbbrMatch = f(c.blue),
	CmpItemAbbrMatchFuzzy = f(c.red),

	CmpItemMenu = f(c.foreground),
	CmpItemKind = f(c.blue),
	CmpItemKindText = f(c.foreground),
	CmpItemAbbrDeprecated = mt(f(c.white), s("strikethrough")),
	CmpItemKindSnippet = f(c.dark_red),
	CmpItemKindUnit = f(c.dark_yellow),
	CmpItemKindProperty = f(c.green),
	CmpItemKindKeyword = f(c.yellow),
	CmpItemKindVariable = f(c.blue),
	-- CmpItemKindField = f(c.foreground),
	CmpItemKindClass = f(c.red),
	CmpItemKindInterface = f(c.extra.teal),
	CmpItemKindFunction = f(c.blue),
	CmpItemKindMethod = f(c.blue),
	CmpItemKindConstant = f(c.green),
	CmpItemKindStruct = f(c.purple),
	CmpDocumentation = b(c.background),
	CmpDocumentationBorder = f(c.blue),
}

hl.plugins.packer = {
	packerFail = f(c.red), -- Icon when install/update fails
	packerSuccess = f(c.green), -- Icon when install/update is a success
	packerWorking = f(c.yellow), -- Icon when syncing
	packerOutput = f(c.blue), -- Text beneath plugin title (e.g. Commits)
	packerStatusFail = f(c.red),
	packerStatusSuccess = f(c.green), -- Plugin name when install/update is a success
}

hl.plugins.gitsigns = {
	GitSignsAdd = link("diffAdded"),
	GitSignsChange = link("diffChanged"),
	GitSiginsDelete = link("diffRemoved"),
}

hl.plugins.telescope = {
	TelescopeBorder = f(c.visual_grey),
	TelescopePromptTitle = fb(c.red, c.background),
	-- TelescopePromptBorder = f(c.visual_grey),
	TelescopeResultsTitle = fb(c.blue, c.background),
	-- TelescopeResultsBorder = f(c.visual_grey),
	TelescopePreviewTitle = fb(c.green, c.background),
	TelescopePreviewBorder = f(c.black),
	TelescopeMatching = mt(fb(c.black, c.dark_yellow), s("bold")),
	TelescopeSelection = f(c.blue),
}

hl.plugins.nvimtree = {
	NvimTreeEndOfBuffer = f(c.background),
	NvimTreeFolderIcon = f(c.blue),
	NvimTreeOpenedFolderName = f(c.red),
	NvimTreeNormal = fb(c.foreground, c.background),
	NvimTreeRootFolder = mt(f(c.red), s("underline")),
}

hl.plugins.blankline = {
	IndentLine = f(c.background),
	IndentBlanklineIndent1 = mt(f("#E06C75"), s("nocombine")),
	IndentBlanklineIndent2 = mt(f("#E5C07B"), s("nocombine")),
	IndentBlanklineIndent3 = mt(f("#98C379"), s("nocombine")),
	IndentBlanklineIndent4 = mt(f("#56B6C2"), s("nocombine")),
	IndentBlanklineIndent5 = mt(f("#61AFEF"), s("nocombine")),
	IndentBlanklineIndent6 = mt(f("#C678DD"), s("nocombine")),
	-- IndentBlanklineChar = f(gc.visual_grey)
}

hl.plugins.ts_rainbow = {
	rainbowcol1 = f(c.red),
	rainbowcol2 = f(c.purple),
	rainbowcol3 = f(c.dark_yellow),
	rainbowcol4 = f(c.green),
	rainbowcol5 = f(c.blue),
	rainbowcol6 = f(c.cyan),
	rainbowcol7 = f(c.yellow),
}
-- hl.plugins.bufferline = {
--   BufferLineTabSelected = fb(gc.black, gc.extra.teal),
--   BufferLineIndicatorSelected = fb(gc.blue, gc.dackground),
--   BufferLineCloseButtonSelected = f(gc.red),
-- }

hl.plugins.whichkey = {
  WhichKey = mt(f(c.purple),s("bold")),
  WhichKeyDesc = f(c.blue),
  WhichKeySeparator = f(c.blue),
  WhichKeyGroup = f(c.red),
  WhichKeyValue = f(c.red),
  WhichKeyFloat = f(c.blue),
}

hl.plugins.notify = {
	NotificationInfo = f(c.blue),
	NotificationWarning = f(c.yellow),
	NotificationError = f(c.red),
}

hl.transparency = {
	Normal = b("NONE"),
	SignColumn = b("NONE"),
	StatusLine = b("NONE"),
	StatusLineTerm = b("NONE"),

	Pmenu = b("NONE"),
	PmenuSbar = b("NONE"),

	NormalFloat = b("NONE"),
	NvimTreeNormal = b("NONE"),
	NvimTreeNormalNC = b("NONE"),
	NvimTreeStatusLineNC = b("NONE"),
	NvimTreeVertSplit = fb(c.grey, "NONE"),
	-- telescope
	TelescopeBorder = fb(c.background, "NONE"),
	TelescopePrompt = b("NONE"),
	TelescopeResults = b("NONE"),
	TelescopePromptNormal = b("NONE"),
	TelescopeNormal = b("NONE"),
	TelescopePromptPrefix = b("NONE"),
	TelescopeResultsTitle = fb(c.black, c.blue),
	TelescopePreviewTitle = fb(c.black, c.green),
	TelescopePromptTitle = fb(c.black, c.red),
}

local function init()
	vim.cmd("hi clear")
	if vim.fn.exists("syntax_on") then
		vim.cmd("syntax reset")
	end
	vim.o.termguicolors = true
	vim.o.background = "dark"
	vim.g.colors_name = "onedark"
	highlight(hl.common)
	highlight(hl.syntax)
	highlight(hl.git)
	highlight(hl.treesitter)
	for _, group in pairs(hl.plugins) do
		highlight(group)
	end
	terminal_color()
	local ts = require("core.config").ui.transparency
	if ts then
		highlight(hl.transparency)
	end
end

init()
